A business may use a web service to interact with other entities via a distributed environment, such as the Internet or World Wide Web. To ensure that such an interaction is accomplished successfully, one or more protocols must be in place for carrying messages to and from participants, and specific business applications must also be in place at each participant's end. Such interactions are message driven. For example, a buyer sends a purchase order to a seller. The seller then checks its inventory to determine if it can provide the ordered items. If so, the seller sends an acknowledgement back to the buyer with a price. Finally, the buyer accepts or rejects the seller's offer (and/or possibly places another order). As evident in this example, each participant's business application reacts to the receipt of messages.
Web services use computer programs based on software code to implement message-based business transactions such as those described above. Such software code is in turn implemented in a programming language. Programming languages typically allow a programmer to declare one or more data objects, such as a variable, that hold the state of the program.
In a message-oriented language that is capable of implementing the business transactions discussed above, a data object may be a message that is received as input from some outside source. Such a message may be quite large, and therefore the storage of multiple data objects may consume a great deal of memory resources. Thus, a data object should be deleted, or “destroyed,” once the data object is no longer needed for the proper operation of the software. Conventionally, destroy points, which are code instructions to destroy one or more data objects, are manually inserted into the software code by a programmer. A programmer will usually select the particular data object to be destroyed and the location within the code where such deletion is to occur. Typically, a programmer will attempt to place the destroy point immediately after the last use of the data object. In such a manner, the data object is retained in memory for as brief a duration as possible.
As a result of being performed manually, such a conventional method of destroying data objects therefore has a potential for human error in the placement of the destroy points and the selection of data objects to be deleted. An additional shortcoming is present in the context of a program that is implementing a message-based transaction. For example, in such a program, messages may be interrupted or other errors may occur that invoke special, “compensation” software components that may resend a message or may attempt some other process to rectify, or compensate for, the error. Compensation components add complexity to the software code, thereby making the programmer's task of selecting the proper location within the code where a destroy point should be located even more difficult. In addition, program code for message-based transactions may be especially complex, with many operations being processed in parallel, with the possibility that some of the operations may not complete or may invoke a compensation component at runtime. Therefore, selecting a location for a destroy point in such a situation is difficult, as every possible logic path that may be taken during processing must be accounted for.
The above description of the shortcomings of conventional placement of destroy points applies equally to “create” and “lock” points, as well as to any other type of data object handling operations. A create point is a location within software code where a data object is created. Ideally, a create point should be placed immediately before the data object is first used, again to reduce the consumption of memory resources. A lock point is a location within software code where a set of shared objects, such as a variable, is made inaccessible to program components that are not involved with a current transaction. In this way, the value(s) assigned to the data object cannot be changed by an outside component during the transaction, which therefore avoids errors during processing. Like create points, lock points should be placed as close to the use of a data object as possible, to avoid locking the variable unnecessarily. However, in software program that implements message-based transactions, an improper placement of a lock point may, in the event of a message error or another type of error, cause the program to have faults or to even stop operating. In complex software, it becomes increasingly difficult for a programmer to keep track of all the possible logic paths and attendant compensation components to place lock points at an optimal location: as close as possible to the use of a data object without being in a location that could cause faults if an error occurs.
As should be known to those skilled in the art, a compiler converts the high-level code used by programmers into a machine-readable language that can be more quickly executed at run time. At compile time, a compiler maps out the different possible logic paths that may be taken by the program to create a flowgraph of such logic paths. The flowgraphs are used for semantic analysis of program correctness and to generate the most efficient code.
A conventional compiler lacks the functionality to analyze a program, and/or produce flowgraphs, in such a way as to be able to determine the optimal placement of create, lock and/or destroy points. In addition, a conventional compiler lacks the ability to insert such points into the program so the corresponding data objects will be created, locked and/or created at the appropriate points at run time.
Accordingly, what is needed is a method for analyzing software, such as XLANG/s, that is capable of implementing message-based transactions in such a way as to be able to determine appropriate points for data object operations. More particularly, what is needed is a method for creating a flowgraph of a program that is capable of supporting analysis of the program's handling of data objects. More particularly, what is needed is a method of compiling computer code that involves generating a flowgraph and performing static data flow analysis on such a flowgraph to determine appropriate create, lock and destroy points for data objects in the program. Even more particularly, what is needed is a compiler that performs such an analysis of a flowgraph associated with such a program and determines whether data object errors will occur at runtime.